package it.txt.ens.namespace;
/***************************************************************************
 * Copyright 2011 TXT e-solutions SpA
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the research area ICT-2009.1.3
 * Internet of Things and enterprise environments.
 *
 * Authors:
 *      Sancesario Raffaele(TXT e-solutions SpA)
 *      Piccione Salvatore(TXT e-solutions SpA)
 *
 * Contributors:
 *        Domenico Rotondi (TXT e-solutions SpA)
 **************************************************************************/


import it.txt.ens.namespace.exception.NamespaceInquirerException;
import it.txt.ens.namespace.exception.SyntaxPatternException;
import it.txt.ens.namespace.osgi.Activator;

import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.orientechnologies.common.concur.lock.OLockManager;
import com.orientechnologies.orient.core.db.graph.OGraphDatabase;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.orient.OrientGraph;
import com.tinkerpop.gremlin.java.GremlinPipeline;
import com.tinkerpop.pipes.PipeFunction;
import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;


public class NamespaceInquirerImpl implements NamespaceInquirer {

//	private  OrientGraph graph;
	
	private final String dbURL;
    
    private final String usr;
    
    private final String psw;
    
//    private final OGraphDatabasePool pool;
    
    private final String CERITFICATE_INDEX_NAME= "CertificateIndex";
    
    private final String NAMESPACE_INDEX_NAME= "NSnameIndex";
    
    private final String CERITFICATE_EDGE_LABEL= "certificate";
    
    private final String NAMESPACE_NAME_PROPERTY="name";

    private final String PLACEHOLDER_ONE_AND_ONE_ONLY = "*";
    
    private final String PLACEHOLDER_AT_LEAST_ONE = "#";
    
    private static final Logger LOGGER = Logger.getLogger(NamespaceInquirerImpl.class.getName());
    private static final ResourceBundle MESSAGES = ResourceBundle.getBundle("message-bundles/" + 
            NamespaceInquirerImpl.class.getSimpleName());
        
    
   /* public static void main(String[] args) {
    	//graph = new OrientGraph("remote:pc-drotondi7:2424/NamespaceDatabase", "admin", "admin");
        // System.out.println(graph.getRawGraph().getURL());
    	NamespaceInquirerImpl pippo = new NamespaceInquirerImpl("remote:pc-drotondi7:2424/NamespaceDatabase", "admin", "admin");
    	//String test= "#";
    	String test= "#.*.#.#.sada.*.*.*";
        //String[] PatternArray= getCheckedPatternArray(test);
    	try {
			pippo.patternExist(test, "Mirafiori Plant");
		} catch (SyntaxPatternException | NamespaceInquirerException e) {
			e.printStackTrace();
		}
    	
	}*/
    
    public NamespaceInquirerImpl (String dbURL, String usr, String psw) {
        this.dbURL = dbURL;
        this.usr = usr;
        this.psw = psw;
        
        //sometimes the following exception is thrown (even with sequential database access...)
//        it.txt.ens.namespace.exception.NamespaceInquirerException: Error while checking the pattern
//        at it.txt.ens.namespace.NamespaceInquirerImpl.patternExist(NamespaceInquirerImpl.java:344)
//        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.executeNamespaceCapabilityCheck(AccessRequestEvaluator.java:596)
//        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.evaluate(AccessRequestEvaluator.java:296)
//        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.run(AccessRequestEvaluator.java:219)
//        at it.txt.ens.authorisationService.util.AccessRequestListener$AccessRequestConsumer.handleDelivery(AccessRequestListener.java:339)
//        at com.rabbitmq.client.impl.ConsumerDispatcher$4.run(ConsumerDispatcher.java:121)
//        at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:76)
//        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
//        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
//        at java.lang.Thread.run(Thread.java:722)
//    Caused by: com.orientechnologies.orient.core.exception.ODatabaseException: Cannot open database
//        at com.orientechnologies.orient.core.db.raw.ODatabaseRaw.open(ODatabaseRaw.java:115)
//        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.open(ODatabaseWrapperAbstract.java:47)
//        at com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract.open(ODatabaseRecordAbstract.java:114)
//        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.open(ODatabaseWrapperAbstract.java:47)
//        at com.orientechnologies.orient.core.db.graph.OGraphDatabase.open(OGraphDatabase.java:90)
//        at com.orientechnologies.orient.core.db.graph.OGraphDatabasePooled.<init>(OGraphDatabasePooled.java:42)
//        at com.orientechnologies.orient.core.db.graph.OGraphDatabasePool.createResource(OGraphDatabasePool.java:39)
//        at com.orientechnologies.orient.core.db.graph.OGraphDatabasePool.createResource(OGraphDatabasePool.java:20)
//        at com.orientechnologies.orient.core.db.ODatabasePoolBase$1.createNewResource(ODatabasePoolBase.java:67)
//        at com.orientechnologies.orient.core.db.ODatabasePoolBase$1.createNewResource(ODatabasePoolBase.java:56)
//        at com.orientechnologies.common.concur.resource.OResourcePool.getResource(OResourcePool.java:66)
//        at com.orientechnologies.orient.core.db.ODatabasePoolAbstract.acquire(ODatabasePoolAbstract.java:65)
//        at com.orientechnologies.orient.core.db.ODatabasePoolAbstract.acquire(ODatabasePoolAbstract.java:53)
//        at com.orientechnologies.orient.core.db.ODatabasePoolBase.acquire(ODatabasePoolBase.java:98)
//        at it.txt.ens.namespace.NamespaceInquirerImpl.patternExist(NamespaceInquirerImpl.java:308)
//        ... 9 more
//    Caused by: java.lang.IllegalThreadStateException
//        at java.lang.ThreadGroup.addUnstarted(ThreadGroup.java:864)
//        at java.lang.Thread.init(Thread.java:387)
//        at java.lang.Thread.<init>(Thread.java:509)
//        at com.orientechnologies.common.thread.OSoftThread.<init>(OSoftThread.java:20)
//        at com.orientechnologies.orient.enterprise.channel.binary.OAsynchChannelServiceThread.<init>(OAsynchChannelServiceThread.java:36)
//        at com.orientechnologies.orient.client.remote.OStorageRemote.createConnectionPool(OStorageRemote.java:1954)
//        at com.orientechnologies.orient.client.remote.OStorageRemote.openRemoteDatabase(OStorageRemote.java:1517)
//        at com.orientechnologies.orient.client.remote.OStorageRemote.open(OStorageRemote.java:176)
//        at com.orientechnologies.orient.client.remote.OStorageRemoteThread.open(OStorageRemoteThread.java:69)
//        at com.orientechnologies.orient.core.db.raw.ODatabaseRaw.open(ODatabaseRaw.java:96)
//        ... 23 more
    }
    

    
    
    /* (non-Javadoc)
     * @see it.txt.ens.namespace.NamespaceInquirer#isTrustedCertificate(java.lang.String, java.lang.String, java.lang.String)
     */
    @Override
    public boolean isTrustedCertificate(String certificateIssuer, String Serialnumber, String namespaceName) throws NamespaceInquirerException {
	    boolean isTrustedCertificate = false;
	    ClassLoader original = null;
//	    System.out.println("DB-0");
        if (Activator.isRunningOnOSGi()) {
            original = Thread.currentThread().getContextClassLoader();
            //Trying to use the class loader of Orient:
//          Exception in thread "Thread-1" java.lang.NullPointerException
//          at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1432)
//          at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
//          at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
//          at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerNew.init(OMMapManagerNew.java:52)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.getInstance(OMMapManagerLocator.java:43)
//          at com.orientechnologies.orient.core.Orient.shutdown(Orient.java:315)
//          at com.orientechnologies.orient.core.OrientShutdownHook.run(OrientShutdownHook.java:28)
//          ClassLoader temp = OIndexes.class.getClassLoader();
            
//          ClassLoader temp = Orient.class.getClassLoader();
//          Exception in thread "Thread-1" java.lang.NullPointerException
//          at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1432)
//          at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
//          at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
//          at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerNew.<init>(OMMapManagerNew.java:43)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.createInstance(OMMapManagerLocator.java:63)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.getInstance(OMMapManagerLocator.java:42)
//          at com.orientechnologies.orient.core.Orient.shutdown(Orient.java:315)
//          at com.orientechnologies.orient.core.OrientShutdownHook.run(OrientShutdownHook.java:28)

//          Exception in thread "Thread-1" java.lang.NullPointerException
//          at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1432)
//          at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
//          at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
//          at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerNew.init(OMMapManagerNew.java:61)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.getInstance(OMMapManagerLocator.java:43)
//          at com.orientechnologies.orient.core.Orient.shutdown(Orient.java:315)
//          at com.orientechnologies.orient.core.OrientShutdownHook.run(OrientShutdownHook.java:28)

//            ClassLoader temp = OFileMMap.class.getClassLoader();
//            Exception in thread "Thread-1" java.lang.NullPointerException
//            at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1432)
//            at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
//            at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
//            at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
//            at com.orientechnologies.orient.core.storage.fs.OMMapManagerNew.init(OMMapManagerNew.java:52)
//            at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.getInstance(OMMapManagerLocator.java:43)
//            at com.orientechnologies.orient.core.Orient.shutdown(Orient.java:315)
//            at com.orientechnologies.orient.core.OrientShutdownHook.run(OrientShutdownHook.java:28)
            
//          ClassLoader temp = OMMapManager.class.getClassLoader();
//          Exception in thread "Thread-1" java.lang.NullPointerException
//          at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1432)
//          at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
//          at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
//          at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerNew.<init>(OMMapManagerNew.java:43)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.createInstance(OMMapManagerLocator.java:63)
//          at com.orientechnologies.orient.core.storage.fs.OMMapManagerLocator.getInstance(OMMapManagerLocator.java:42)
//          at com.orientechnologies.orient.core.Orient.shutdown(Orient.java:315)
//          at com.orientechnologies.orient.core.OrientShutdownHook.run(OrientShutdownHook.java:28)
            Thread.currentThread().setContextClassLoader(OLockManager.class.getClassLoader());
        }
        OGraphDatabase db = null;
        OrientGraph g = null;
	    try {
//            System.out.println("DB-1");
            db = new OGraphDatabase(dbURL);
//            db = pool.acquire();
//            System.out.println("DB-1B");
            db.open(usr, psw);
//            System.out.println("DB-2");
            g = new OrientGraph(db);
//            System.out.println("DB-3");
			namespaceName = namespaceName.replace("\"","\\\"" );
//            System.out.println("DB-4");
			// Query to select the certificate from the index
			String query =  "select from index:" + CERITFICATE_INDEX_NAME + " where key = \"" + certificateIssuer + Serialnumber + "\"";
			if (LOGGER.isLoggable(Level.FINER))
			    LOGGER.finer(MessageFormat.format(MESSAGES.getString("trustworhinessQuery"), query));
//            System.out.println("DB-5");
		    List<ODocument> queryResult = db.query( new OSQLSynchQuery<ODocument>(query));
//            System.out.println("DB-6");
			if (!queryResult.isEmpty()){
//	            System.out.println("DB-6A");
	            //if query results is not empty take the vertex
				Vertex certificateV =g.getVertex(queryResult.get(0).field("rid",ORID.class).toString());
//	            System.out.println("DB-6B");
				Iterable<Edge> certificateEdgeList = certificateV.getEdges(Direction.IN, CERITFICATE_EDGE_LABEL);
//                System.out.println("DB-6C");
				//cycle to verify whether the certificate is associated with the namespace provided as input
				Iterator<Edge> iterator = certificateEdgeList.iterator();
//                System.out.println("DB-6D");
				while (iterator.hasNext() && !isTrustedCertificate) {
//	                System.out.println("DB-6DA");
					Edge certificateE = (Edge) iterator.next();
//                    System.out.println("DB-6DB");
					Vertex namespaceV = certificateE.getVertex(Direction.OUT);
//                    System.out.println("DB-6DC");
					if (namespaceV.getProperty(NAMESPACE_NAME_PROPERTY).equals(namespaceName)){
//	                    System.out.println("DB-6DD");
						isTrustedCertificate = true;
					}
				}
			}
//            System.out.println("DB-7");
	    } catch (Throwable e) {
            LOGGER.log(Level.SEVERE, "Error while checking the certificate", e);
			 throw new NamespaceInquirerException("Error while checking the certificate",e);
		} finally {
		    if (g == null) {
//                System.out.println("DB-8");
                if (db != null) {
                    db.close();
//                    System.out.println("DB-9");
                }
		    } else {
		        g.shutdown();
//                System.out.println("DB-10");
             }
			 if (original != null)
			     Thread.currentThread().setContextClassLoader(original);
		}	
	    return isTrustedCertificate;
	}
	
	
	/* (non-Javadoc)
	 * @see it.txt.ens.namespace.NamespaceInquirer#patternExist(java.lang.String, java.lang.String)
	 */
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public boolean patternExist (String PatternToBeVerified, String namespaceName) throws SyntaxPatternException, NamespaceInquirerException {
		boolean patternExist=false;
        ClassLoader original = null;
//        System.out.println("DB0");
        if (Activator.isRunningOnOSGi()) {
            original = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(OLockManager.class.getClassLoader());
        }
        OGraphDatabase db = null;
        OrientGraph g = null;
		try {
//	        System.out.println("DB1");
	        
	        //Setting the ODatabaseRecordThreadLocal before or after creating the DB or not setting it
	        //causes the following exception:
//	        com.orientechnologies.orient.core.exception.ODatabaseException: Cannot open database
//	        at com.orientechnologies.orient.core.db.raw.ODatabaseRaw.open(ODatabaseRaw.java:115)
//	        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.open(ODatabaseWrapperAbstra
//	ct.java:47)
//	        at com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract.open(ODatabaseRecordA
//	bstract.java:114)
//	        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.open(ODatabaseWrapperAbstra
//	ct.java:47)
//	        at com.orientechnologies.orient.core.db.graph.OGraphDatabase.open(OGraphDatabase.java:90)
//	        at it.txt.ens.namespace.NamespaceInquirerImpl.patternExist(NamespaceInquirerImpl.java:284)
//	        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.executeNamespaceCapabilityChe
//	ck(AccessRequestEvaluator.java:575)
//	        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.evaluate(AccessRequestEvaluat
//	or.java:282)
//	        at it.txt.ens.authorisationService.util.AccessRequestEvaluator.run(AccessRequestEvaluator.ja
//	va:215)
//	        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
//	        at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
//	        at java.util.concurrent.FutureTask.run(Unknown Source)
//	        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
//	        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
//	        at java.lang.Thread.run(Unknown Source)
//	Caused by: java.lang.IllegalThreadStateException
//	        at java.lang.ThreadGroup.addUnstarted(Unknown Source)
//	        at java.lang.Thread.init(Unknown Source)
//	        at java.lang.Thread.<init>(Unknown Source)
//	        at com.orientechnologies.common.thread.OSoftThread.<init>(OSoftThread.java:20)
//	        at com.orientechnologies.orient.enterprise.channel.binary.OAsynchChannelServiceThread.<init>
//	(OAsynchChannelServiceThread.java:36)
//	        at com.orientechnologies.orient.client.remote.OStorageRemote.createConnectionPool(OStorageRe
//	mote.java:1954)
//	        at com.orientechnologies.orient.client.remote.OStorageRemote.openRemoteDatabase(OStorageRemo
//	te.java:1517)
//	        at com.orientechnologies.orient.client.remote.OStorageRemote.open(OStorageRemote.java:176)
//	        at com.orientechnologies.orient.client.remote.OStorageRemoteThread.open(OStorageRemoteThread
//	.java:69)
//	        at com.orientechnologies.orient.core.db.raw.ODatabaseRaw.open(ODatabaseRaw.java:96)
//	        ... 14 more
	        
	        db = new OGraphDatabase(dbURL).open(usr, psw);
//	        db = pool.acquire();
//            System.out.println("DB1B");
//            System.out.println("DB1C");
	        g = new OrientGraph(db);
//			if (this.graph != null)
//			    this.graph = new OrientGraph(dbURL, usr, psw);
			
//            System.out.println("DB2");
			// Query to select the namespace from the index
			String query =  "select from index:" + NAMESPACE_INDEX_NAME + " where key = \"" + namespaceName + "\"";
			if (LOGGER.isLoggable(Level.FINER))
                LOGGER.finer(MessageFormat.format(MESSAGES.getString("patternExistenceQuery"), query));
//			List<ODocument> queryResult = graph.getRawGraph().query( new OSQLSynchQuery<ODocument>(query));
			List<ODocument> queryResult = db.query( new OSQLSynchQuery<ODocument>(query));
//            System.out.println("DB3");
			if (!queryResult.isEmpty()) {
//			    g = new OrientGraph(db);
//	            System.out.println("DB4");
			    
				//if query results is not empty take the namespace vertex
//				Vertex namespaceV = graph.getVertex(queryResult.get(0).field("rid",ORID.class).toString());
			    Vertex namespaceV = g.getVertex(queryResult.get(0).field("rid",ORID.class).toString());
//	            System.out.println("DB5");
				// get checked pattern array (verify that there are two consecutive #)
				String[] CheckedPatternArray = getCheckedPatternArray(PatternToBeVerified);
//	            System.out.println("DB6");
				// get the pipeline to validate pattern
				GremlinPipeline validatePatternPipeline = createPipelineForValidatePattern(CheckedPatternArray,namespaceV);
//	            System.out.println("DB7");
				//  Execute pipeline
				patternExist = ExecutePipelineForValidatePattern(validatePatternPipeline);
//	            System.out.println("DB8");
			}
		 } catch (Throwable e) {
		     LOGGER.log(Level.SEVERE, "Error while checking the pattern", e);
			 throw new NamespaceInquirerException("Error while checking the pattern",e);
		 } finally {
//			 if (this.graph!=null) {
//				 graph.shutdown();
//			     if (original != null)
//			         Thread.currentThread().setContextClassLoader(original);
//			 }
		     if (g == null) {
//		            System.out.println("DB9");
		         if (db != null) {
		             if (!db.isClosed()) {
//	                     System.out.println("DB9A");
		                 db.close();
//                         System.out.println("DB9B");
		             }
//                     System.out.println("DB10");
		         }
//                 System.out.println("DB10A");
		     } else {
		         g.shutdown();
//		            System.out.println("DB11");
		     }
             if (original != null)
                 Thread.currentThread().setContextClassLoader(original);
//             System.out.println("DB12");
		 }
		 return patternExist;
	}
	
	
	private boolean ExecutePipelineForValidatePattern (GremlinPipeline<Object, Vertex> pipe){
		return pipe.hasNext();
	}
	

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private GremlinPipeline createPipelineForValidatePattern(String[] PatternArray, Vertex namespaceV){
		GremlinPipeline pipe = new GremlinPipeline(namespaceV);
	    int i = 0;
		while( i < PatternArray.length) {
		   if (!PatternArray[i].equals(PLACEHOLDER_AT_LEAST_ONE)&&!PatternArray[i].equals(PLACEHOLDER_ONE_AND_ONE_ONLY)){
		    	 // if the current segment is different from # or *, verify that there is  a node in a namespace with equal name
			     pipe.out().has("name",PatternArray[i]);
//			     System.out.println("Add pipe.out().has(\"name\","+PatternArray[i]+")");
		    	 i++;
		   }else {
			   // if the current segment is # or *
			   boolean loopNeeded = false;
			   // until you find placeholders
			   while ((PatternArray.length-(i))!=0 && (PatternArray[i].equals(PLACEHOLDER_AT_LEAST_ONE)||PatternArray[i].equals(PLACEHOLDER_ONE_AND_ONE_ONLY))){
				  if (PatternArray[i].equals(PLACEHOLDER_ONE_AND_ONE_ONLY)){
				      //if segment equal '*' add pipe.out() 
					  pipe.out();
//					  System.out.println("Add pipe.out()");
					  i++;
				  }else { 
					  //if find # set loopNeede = true to add subsequently the loop in the pipe
					  loopNeeded=true;
					  i++;
				  }
			   }
			   if (loopNeeded && (PatternArray.length-(i))!=0){
				   // if loopNeede = true and the pattern does not end with #
				   final String nextSectionOfPath=PatternArray[i];
//				   System.out.println("Add LoopPipe([OutPipe])");
				   pipe.out().loop(1,  new PipeFunction<LoopBundle<Vertex>, Boolean>() {
				   @Override
				   public Boolean compute(LoopBundle<Vertex> arg0) {
						Vertex v = arg0.getObject();
						if((v.getProperty(NAMESPACE_NAME_PROPERTY)!=null)&&(v.getProperty(NAMESPACE_NAME_PROPERTY).equals(nextSectionOfPath))){
							  return false;
						}
						return true;
					}});
					i++;
			   }
		    }
        }
//		System.out.println(pipe);
		return pipe;
   }
	
	
	private  String[] getCheckedPatternArray(String PatternToBeVerified) throws SyntaxPatternException {
		String[] PatternArray = PatternToBeVerified.split("[.]");
		for (int i = 0; i < PatternArray.length; i++) {
			String currentSectionOfPattern = PatternArray[i]; 
			if (PatternArray.length-(i+1)>0){
				String nextSectionOfPattern = PatternArray[i+1];
				if(currentSectionOfPattern.endsWith(PLACEHOLDER_AT_LEAST_ONE)&&
				        nextSectionOfPattern.endsWith(PLACEHOLDER_AT_LEAST_ONE)){
					throw new SyntaxPatternException("The pattern has more than one " + PLACEHOLDER_AT_LEAST_ONE + " in sequence.");
				}
			}
		}
		return PatternArray;
	}	
}